# -*- encoding:utf-8 -*-
# __author__ = 'chenyongbing'
# __poject__ = 'ops_platform'
# __datetime__ = '2022/2/23'
# __name__ = 'mixin.py'
import sys
import re
import json
import random
from django.db import transaction
from ..models import WorkOrderStep
from apps.cicd.handles.base import workorder_step_opuser
import logging
# Create your code here.

'''
Stage 状态:    wait ->  process -> [ finish | success ]
Step 状态:     wait ->  process -> [ finish | success | error ]
WorkOrder状态:  wait -> process -> [ finish | success ]
'''


class FlowMixin():
    def __init__(self, workorder, username, git_merge=0):
        self.workorder = workorder
        self.flow = self._get_flow_obj()
        self.username = username
        self.git_merge = git_merge


    def _logging_debug(self, msg):
        logging.debug("工单: {}, {}".format(self.workorder.id, msg))

    def _logging_info(self, msg):
        logging.info("工单: {}, {}".format(self.workorder.id, msg))

    def _logging_warn(self, msg):
        logging.warning("工单: {}, {}".format(self.workorder.id, msg))

    def _logging_error(self, msg):
        logging.error("工单: {}, {}".format(self.workorder.id, msg))

    def _logging_exception(self, msg):
        logging.exception("工单: {}, {}".format(self.workorder.id, msg))
    def _get_current_workorder_step(self):
        '''获取当前workorder步骤'''
        return self.workorder.steps.last()

    def _get_current_step_obj(self, step_function=None):
        '''获取当前步骤obj'''
        if step_function == None:
            return self.workorder.steps.last().step
        else:
            return self.flow.steps.get(function=step_function)
    def _get_flow_obj(self):
        '''获取流程obj'''
        return self.workorder.get_flow_obj()

    # def _get_env_list(self):
    #     '''获取环境列表'''
    #     return self.workorder.envs.split(',')

    def _get_next_step_obj(self, current_step, action='yes'):
        '''获取下一个步骤'''
        next_step = getattr(current_step, '%s_step'%(action))
        if not next_step:return next_step
        next_step_function = next_step.function
        if next_step_function == 'exec__git_merge_auto' and self.git_merge == 0:
            return self._get_next_step_obj(next_step, action='yes')
        return next_step

    def is_step_valid(self, step_function, action='yes'):
        '''校验步骤执行是否合法'''
        current_workorder_step = self._get_current_workorder_step()
        if  current_workorder_step.opuser != 'auto' and self.username not in current_workorder_step.opuser.split(','):
            return False
        if current_workorder_step.step.function != step_function:
            return False
        if current_workorder_step.status not in ['wait', 'fail']:
            return False
        if action == 'retry':
            return True
        step_obj = self._get_step_obj(step_function)
        if not getattr(step_obj, '%s_button'%action) and current_workorder_step.status != 'fail':
            return False

        return True
    def _get_step_obj(self, full_function):
        '''根据function获取step'''
        return self._get_current_step_obj(full_function)


    def _get_non_execution_steps(self, last_step):
        '''获取未执行步骤'''
        steps = []
        if last_step == None:
            last_step = self.flow.steps.get(function='init')
        while 1:
            # next_step = last_step.yes_step
            next_step = self._get_next_step_obj(last_step, 'yes')
            if not next_step: break

            steps.append({
                'step_name': next_step.name,
                'step': next_step.function,
                # 'opuser': next_step.opuser,
                'status': 'wait'
            })
            last_step = next_step
            if last_step.function == 'cancel': break
        return steps

    # def __is_need_audit(self):
    #     audit = 1
    #     business_id = self.workorder.service.business.id
    #     lobsetting = LobEnvSetting.objects.filter(business_id=business_id, env_id=self.workorder.env_id,
    #                                               project_id__isnull=True, service_id__isnull=True).first()
    #     if lobsetting and lobsetting.auto_audit == 1:
    #         audit = 0
    #     return audit
    #
    # def __get_step_opuser(self, step, username):
    #     if re.search('auto', step.function):
    #         return 'auto'
    #     perm_role = step.perm_role
    #     if perm_role == None:
    #         return username
    #     if re.search('audit', step.function):
    #         audit = self.__is_need_audit()
    #         if not audit:
    #             return 'auto'
    #
    #     business = self.workorder.service.business
    #     roleids = []
    #     for role_code in perm_role.split(','):
    #         role = Role.objects.get(code=role_code)
    #         roleids.append(role.id)
    #     users = []
    #     for perm in LobPerm.objects.filter(business=business, roles__in=roleids):
    #         username = perm.user.username
    #         users.append(username)
    #     return ','.join(users)



    def do(self, step_function, action='retry', comment=''):
        '''
        执行步骤、步骤扭转 cur \ next
        :param step_function:
        :param action:
        :param comment:
        :return:
        '''

        is_finish = False
        is_cancel = False
        # 获取当前步骤
        cur_workorder_step = self._get_current_workorder_step()

        # 更新当前步骤为process
        if not cur_workorder_step:
            cur_step = self.flow.steps.get(function=step_function)
            cur_workorder_step = WorkOrderStep(workorder=self.workorder,
                                               step_id=cur_step.id,
                                               opuser=self.username,
                                               status='process')
            cur_workorder_step.save()
        else:
            cur_workorder_step.status = 'process'
            if cur_workorder_step.opuser != 'auto':
                cur_workorder_step.opuser = self.username
            cur_workorder_step.save()
            # workorder, stage_name, step_name, step_function, step_env, opuser, status, result
            cur_step = cur_workorder_step.step

        # 执行当前步骤
        # cur_step_status, cur_step_result = getattr(self, step_function)(action=action)
        try:
            cur_step_status, cur_step_result = getattr(self, step_function)(action=action)
        except Exception as err:
            self._logging_exception(err)
            cur_step_status = 'fail'
            cur_step_result = 'fail'
        # 更新当前步骤状态结果
        # cur_workorder_step.status = 'wait' if cur_step_status == 'fail' else cur_step_status
        cur_workorder_step.status = cur_step_status
        cur_workorder_step.result = cur_step_result
        cur_workorder_step.save()

        # 更新下一步骤
        if cur_step_status in ['finish', 'success']:
            with transaction.atomic():
                # 获取next步骤
                next_step = self._get_next_step_obj(current_step=cur_step, action=action)

                next_step_function = next_step.function
                next_step_name = next_step.name
                nex_step_status = 'wait'
                if next_step_function == 'end__finish':
                    is_finish = True
                    nex_step_status = 'finish'
                elif next_step_function == 'end__cancel':
                    is_cancel = True
                    nex_step_status = 'finish'

                opuser = workorder_step_opuser(workorder=self.workorder, step=next_step, username=self.username)
                # opuser = self.__get_step_opuser(step=next_step, username=self.username)
                next_workorderstep = {'workorder': self.workorder,
                                      'step_id': next_step.id,
                                      'opuser': opuser,
                                      'status': nex_step_status
                                      }

                WorkOrderStep.objects.update_or_create(defaults=next_workorderstep,
                                                       workorder=self.workorder,
                                                       step_id=next_step.id)

                if is_finish:
                    self.workorder.status = 'finish'
                    self.workorder.save()
                if is_cancel:
                    self.workorder.status = 'cancel'
                    self.workorder.save()
        else:
            next_step = cur_step
        return {'step_status': cur_step_status, 'status': self.workorder.status, 'next_step_function': next_step.function}
    def full_steps(self):
        '''
        完整步骤包含（已确定步骤+模拟未确定步骤）
        :return:
        '''
        steps = []
        cur_workorder_step = None
        # 从工单步骤表获取当前已执行步骤
        for wkstep in self.workorder.steps.all().order_by('id'):

            steps.append({
                'step_name': wkstep.step.name,
                'status': wkstep.status,
                'opuser': wkstep.opuser,
                'step_function': wkstep.step.function
            })
            cur_workorder_step = wkstep

        # 模拟未确定的步骤，从步骤表中模拟
        cur_step = cur_workorder_step.step
        # steps += self.flow.get_steps(cur_step)
        steps += self._get_non_execution_steps(cur_step)
        buttons = []
        if cur_workorder_step:
            button_disable = True if cur_workorder_step.opuser == 'auto' or self.username not in cur_workorder_step.opuser.split(',') else False
        else:
            button_disable =''
        # 获取当前步骤按钮
        if cur_workorder_step.status == 'wait':
            if cur_step.yes_button:
                buttons.append({'name': cur_step.yes_button, 'action': 'yes', 'step_id': cur_step.id,
                                'step_function': cur_step.function,
                                'disable': button_disable})
            if cur_step.no_button:
                buttons.append({'name': cur_step.no_button, 'action': 'no', 'step_id': cur_step.id,
                                'step_function': cur_step.function,
                                'disable': button_disable})
        elif (cur_workorder_step.status == 'fail' or cur_workorder_step.result == 'fail') and cur_step.function.split('__')[-1] != 'cancel':
            buttons.append({'name': '重试', 'action': 'yes', 'step_id': cur_step.id,
                            'step_function': cur_step.function, 'disable': button_disable})
        datas = {'steps': steps,
                 'buttons': buttons}
        return datas





    def init(self):
        '''
        初始化
        :return:
        '''
        step_obj = self.flow.steps.get(function='init').yes_step
        ret = self.do(step_function='%s'%(step_obj.function), action='yes')
        return ret



    def start__apply(self, action='yes'):
        '''
        :param action: only yes
        :return: step_status, step_result
        '''
        return 'finish', 'success'

    def start__audit(self, action='yes'):
        '''
        审核步骤
        :param action: yes or no
        :return: step_status, step_result
        '''
        if action == 'yes':
            return 'finish', 'success'
        else:
            return 'finish', 'error'





    def exec__update(self, action='yes'):
        '''
        确认update，包含执行update调用
        :param action:
        :return:
        '''
        if action == 'no':
            return 'finish', 'error'

        return 'finish', 'success'

    def exec__update_auto(self, action='yes'):
        '''
        自动执行，并完成结果查询，异步
        :return:
        '''
        return 'process', 'process'
        #### 此处调用异步任务运行更新


    def exec__testing(self, action='yes'):
        if action == 'no':
            return 'finish', 'error'
        return 'finish', 'success'

    def exec__rollback(self, action='yes'):
        if action == 'no':
            return 'finish', 'error'
        return 'finish', 'success'

    def exec__rollback_auto(self, action='yes'):
        if action == 'no':
            return 'finish', 'error'
        return 'finish', 'success'


    def end__finish(self, action='yes'):
        if action == 'no':
            return 'finish', 'error'
        return 'finish', 'success'

    def end__cancel(self, action='yes'):
        if action == 'no':
            return 'finish', 'error'
        return 'finish', 'success'


    def exec__restart(self, action='yes'):
        '''
        确认update，包含执行update调用
        :param action:
        :return:
        '''
        if action == 'no':
            return 'finish', 'error'

        return 'finish', 'success'

    def exec__restart_auto(self, action='yes'):
        '''
        自动执行，并完成结果查询，异步
        :return:
        '''
        return 'process', 'process'
        #### 此处调用异步任务运行更新